#pragma once
#include "Socket.hpp"
#include "TcpServer.hpp"
#include "InetAddr.hpp"
#include "Util.hpp"
#include <sstream>

const std::string gspace = " ";
const std::string glinesep = ": ";
const std::string glinespace = "\r\n";
const std::string webroot = "./wwwroot";
const std::string homepage = "index.html";
const std::string page_404 = "/404.html";
const std::string temp = "?";

namespace kzz
{
    class HttpRequest
    {
    public:
        std::string Serialize()
        {
            return std::string();
        }

        // 首行请求做反序列化
        void ParseReqLine(std::string &reqline)
        {
            // 首行:[方法]+[url]+[版本]
            std::stringstream ss(reqline);
            ss >> _method >> _uri >> _version;
        }

        std::string Uri()
        {
            return _uri;
        }

        //
        bool DeSerialize(std::string &reqstr)
        {
            // 获取首行
            std::string reqline;
            bool ret = kzz::Util::ReadOneLine(reqstr, reqline, glinespace);

            if (!ret)
            {
                std::cout << "没找到换行符" << std::endl;
            }
            // 首行请求做反序列化
            ParseReqLine(reqline);

            // 判断uri是否是/
            // 是/的话就直接访问首页

            if (_uri == "/")
            {
                _uri = (webroot + _uri + homepage);
            } //.wwwroot/index.html
            else
            {
                _uri = (webroot + _uri);
            } //.wwwroot/a/b/c

            //.wwwroot/a/b/c?name=111&password=123
            auto pos = _uri.find(temp);
            if (pos == std::string::npos)
            {
                isInteract = false;
                return true;
            }
            // 走到这是需要互动的

            _args = _uri.substr(pos + temp.size());
            isInteract = true;
            _uri = _uri.substr(0, pos);

            return true;
        }

    public:
        bool IsInteract()
        {
            return isInteract;
        }
        std::string Args() const
        {
            return _args;
        }

    private:
        // 首行:[方法]+[url]+[版本]
        std::string _method;
        std::string _uri; // 要访问资源路径
        std::string _version;

        std::unordered_map<std::string, std::string> _headers;
        std::string _blankline;
        std::string _text;

        std::string _args;
        bool isInteract;
    };

    class HttpResPonse
    {
    public:
        // 获取文件后缀
        std::string Uri2Suffix(std::string &targetfile)
        {
            auto pos = targetfile.rfind(".");

            std::string suffix = targetfile.substr(pos);

            if (suffix == ".html" || suffix == ".htm")
                return "text/html";
            if (suffix == ".jpg")
                return "image/jpeg";
            if (suffix == ".png")
                return "image/png";
            else
                return "";
        }
        void SetHeader(const std::string &key, const std::string &value)
        {
            if (_headers.find(key) != _headers.end())
                return;

            _headers.insert(std::make_pair(key, value));
        }

        void SetCode(int code)
        {
            _code = code;

            switch (code)
            {
            case 200:
                _desc = "OK";
                break;
            case 404:
                _desc = "Not Found";
                break;
            case 302:
                _desc = "See Other";
                break;
            default:
                _desc = "";
            }
        }

    public:
        HttpResPonse(std::string blankline = glinespace)
            : _blankline(glinespace), _version("HTTP/1.1")
        {
        }

        std::string Serialize()
        {
            std::string status_line = _version + gspace + std::to_string(_code) + gspace + _desc + glinespace;
            std::string resp_header;
            for (auto e : _headers)
            {
                resp_header += e.first + glinesep + e.second;
                resp_header += glinespace;
            }

            return status_line + resp_header + _blankline + _text;
        }
        void SetTarget(const std::string &filename)
        {
            _targetfile = filename;
        }

        void SetText(const std::string &text)
        {
            _text = text;
        }

        void MakeResPonse()
        {
            bool ret = kzz::Util::ReadFileContent(_targetfile, _text);

            if (_targetfile == "./wwwroot/redir_test")
            {
                SetCode(301);
                SetHeader("Location", "https://news.qq.com/rain/a/UTR2025061303848300");
                return;
            }
            // 游览器请求的的资源不一定存在
            if (!ret)
            {
                // SetCode(404);

                // SetTarget(webroot+page_404);
                // kzz::Util::ReadFileContent(_targetfile, _text);

                // std::string suffix=Uri2Suffix(_targetfile);
                // SetHeader("Conent-Type",suffix);

                // int filesize=kzz::Util::FileSize(_targetfile);
                //  SetHeader("Content-Length",std::to_string(filesize));

                SetCode(302);
                SetHeader("Location", "/404.html");
                SetHeader("Set-Cookie", "username=kzz");
            }

            else
            {
                SetCode(200);

                std::string suffix = Uri2Suffix(_targetfile);
                SetHeader("Conent-Type", suffix);

                int filesize = kzz::Util::FileSize(_targetfile);
                SetHeader("Content-Length", std::to_string(filesize));

                SetHeader("Connection", "keep-alive");
            }
        }

        ~HttpResPonse()
        {
        }

        // 首行:[版本号]+[状态码]+[状态码解释]
    private:
        std::string _version;
        int _code;         // 状态码
        std::string _desc; // 状态码描述符

        std::unordered_map<std::string, std::string> _headers;
        std::string _blankline;
        std::string _text;

        std::string _targetfile;
    };
    using http_func = std::function<void(HttpRequest &, HttpResPonse &)>;

    class Http
    {
    public:
        Http(uint16_t port)
            : _ser(std::make_unique<kzz::TcpServer>(port))
        {
        }

        void HandlerHttpRquest(std::shared_ptr<Socket> &client_fd, InetAddr &client_addr)
        {
            while (true)
            {
                std::string reqstr;
                int n = client_fd->Recv(reqstr);
                if (n == 0)
                {
                    std::cout << "对端关闭" << std::endl;
                    break;
                }
                ///////////////////////////////////////////
                std::cout<<client_fd->Fd()<<std::endl;
                std::cout << reqstr.c_str() << std::endl;
                //////////////////////////////////////////
                kzz::HttpRequest hreq;
                hreq.DeSerialize(reqstr);
                kzz::HttpResPonse hrep;
                std::string uri = hreq.Uri();

                if (hreq.IsInteract())
                {
                    // 需要互动
                    ////   /register?username=233071401113&email=
                    if (_route.find(uri) == _route.end())
                    {
                        hrep.SetTarget(uri);
                        hrep.MakeResPonse();
                        std::string repstr = hrep.Serialize();

                        // std::cout << repstr.c_str() << std::endl;
                        client_fd->Send(repstr);
                    }
                    else
                    {
                        _route[uri](hreq, hrep);
                        std::string repstr = hrep.Serialize();

                        // std::cout << repstr.c_str() << std::endl;
                        client_fd->Send(repstr);
                    }
                }
                else
                {

                    hrep.SetTarget(uri);
                    hrep.MakeResPonse();
                    std::string repstr = hrep.Serialize();

                    // std::cout << repstr.c_str() << std::endl;
                    client_fd->Send(repstr);
                }
            }
        }

        void RegisterService(const std::string &name, http_func service)
        {

            std::string key = webroot + name;
            if (_route.find(key) != _route.end())
                return;

            _route.insert(std::make_pair(key, service));
        }

        void Start()
        {

            _ser->Start([this](std::shared_ptr<Socket> &client_fd, InetAddr &client_addr)
                        { HandlerHttpRquest(client_fd, client_addr); });
        }
        ~Http()
        {
        }

    private:
        std::unique_ptr<kzz::TcpServer> _ser;
        std::unordered_map<std::string, http_func> _route;
    };
}